package com.CTAtracker.android.XML;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Log;
import android.util.Xml;

/**
 * The class that parse the response of the API call.
 * This class extends Observable to return the data to the adapter 
 */
public class APIXmlParser extends Observable {
	/**
	 * the nameSpace
	 */
	private static final String _ns = null;
	/**
	 * The internet Header return by the API
	 */
    private InternetHeader _internetHeader;
    /**
     * The list of Estimate Time of Arrival return by the API
     */
    private ArrayList<InternetETA> _listInternetETA;
    /**
     * Log
     */
    private static final String TAG = "APIXmlParser";
    
    /**
     * Constructor. Create both internet header and list of InternetETA
     */
    public APIXmlParser(){
    	_internetHeader = new InternetHeader();
    	_listInternetETA = new ArrayList<InternetETA>();
    }
    
    /**
     * Parse the XML stream 
     * @param in the XML stream
     * @throws XmlPullParserException
     * @throws IOException
     */
    public void parse(InputStream in) throws XmlPullParserException, IOException {
        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
            parser.setInput(in, null);
            parser.nextTag();
            readFeed(parser);
            setChanged();
        } finally {
            in.close();
        }
        this.notifyObservers();
    }
    
    /**
     * Read the XML stream and instantiate the value of the class 
     * @param parser the XMLPullParser
     * @throws XmlPullParserException
     * @throws IOException
     */
    private void readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
        String name;
        parser.require(XmlPullParser.START_TAG, _ns, InternetData.CTATT);
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            name = parser.getName();
            // Starts by looking for the entry tag
            if (name.equals(InternetData.TIME_STAMP)) {
                _internetHeader.readETA(parser);
            } else if (name.equals(InternetData.ERROR_CODE)){
                _internetHeader.readCodeError(parser);
            } else if (name.equals(InternetData.ERROR_MESSAGE)){
            	if (_internetHeader.get_errorCode() != 0)
            		_internetHeader.readMessageError(parser);
            	else 
            		APIXmlParser.skip(parser);
            } else if (name.equals(InternetData.ESTIMATE_TIME_ARRIVAL)){
            	_listInternetETA.add(readETA(parser));
            }
        }
    }
    
    /**
     * The the header of the API response
     * @param parser the XmlPullParser
     * @return the InternetHeader
     * @throws XmlPullParserException
     * @throws IOException
     */
    private InternetETA readETA(XmlPullParser parser) throws XmlPullParserException, IOException{
    	InternetETA internetETA = new InternetETA();
    	
    	String name;
        parser.require(XmlPullParser.START_TAG, _ns, InternetData.ESTIMATE_TIME_ARRIVAL);
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            name = parser.getName();
            // Starts by looking for the entry tag
            if (name.equals(InternetData.STAID)) {
            	internetETA.readSTAID(parser);
            } else if (name.equals(InternetData.STPID)){
            	internetETA.readSTPID(parser);
            } else if (name.equals(InternetData.STANM)){
            	internetETA.readSTANM(parser);
            } else if (name.equals(InternetData.STPDE)){
            	internetETA.readSTPDE(parser);
            } else if (name.equals(InternetData.RN)){
            	internetETA.readRN(parser);
            } else if (name.equals(InternetData.RT)){
            	internetETA.readRT(parser);
            } else if (name.equals(InternetData.DESTST)){
            	internetETA.readDESTST(parser);
            } else if (name.equals(InternetData.DESTNM)){
            	internetETA.readDESTNM(parser);
            } else if (name.equals(InternetData.TRDR)){
            	internetETA.readTRDR(parser);
            } else if (name.equals(InternetData.PRDT)){
            	internetETA.readPRDT(parser);
            } else if (name.equals(InternetData.ARRT)){
            	internetETA.readARRT(parser);
            } else if (name.equals(InternetData.ISAPP)){
            	internetETA.readISAPP(parser);
            } else if (name.equals(InternetData.ISSCH)){
            	internetETA.readISSCH(parser);
            } else if (name.equals(InternetData.ISDLY)){
            	internetETA.readISDLY(parser);
            } else if (name.equals(InternetData.ISFLT)){
            	internetETA.readISFLT(parser);
            } else {
            	APIXmlParser.skip(parser);
            }
        }
        return internetETA;
    }
    
    // For the tags title and summary, extracts their text values.
    public static String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
        String result = "";
        if (parser.next() == XmlPullParser.TEXT) {
            result = parser.getText();
            parser.nextTag();
        }
        return result;
    }
    
    /**
     * Read an int from the parser
     * @param parser the XmlPullParser
     * @return the value of the int read
     * @throws XmlPullParserException
     * @throws IOException
     */
    public static int readInt(XmlPullParser parser) throws XmlPullParserException, IOException{
    	String result = "1" ;
    	if(parser.next() == XmlPullParser.TEXT){
    		result = parser.getText(); 
    		parser.nextTag();
    	}
    	int res = Integer.parseInt(result);
    	return res;
    }

    // Skips tags the parser isn't interested in. Uses depth to handle nested tags. i.e.,
    // if the next tag after a START_TAG isn't a matching END_TAG, it keeps going until it
    // finds the matching END_TAG (as indicated by the value of "depth" being 0).
    public static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
        if (parser.getEventType() != XmlPullParser.START_TAG) {
            throw new IllegalStateException();
        }
        int depth = 1;
        while (depth != 0) {
            switch (parser.next()) {
            case XmlPullParser.END_TAG:
                    depth--;
                    break;
            case XmlPullParser.START_TAG:
                    depth++;
                    break;
            }
        }
    }

	public InternetHeader getInternetHeader() {
		return _internetHeader;
	}

	public void setInternetHeader(InternetHeader internetHeader) {
		_internetHeader = internetHeader;
	}

	public ArrayList<InternetETA> getListInternetETA() {
		return _listInternetETA;
	}

	public void setListInternetETA(ArrayList<InternetETA> listInternetETA) {
		_listInternetETA = listInternetETA;
	}
	
	
	
    @Override
	public void addObserver(Observer observer) {
		super.addObserver(observer);
		Log.v(TAG, "Add observer of type " + observer.getClass().toString());
	}

	@Override
	public void notifyObservers() {
		super.notifyObservers(_listInternetETA);
		Log.v(TAG, "Notify the observers");
	}

}
